/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ru.niir.goodfil.ui;

import java.util.*;
import java.io.*;

import ru.niir.goodfil.db.DataExchange;
import ru.niir.goodfil.exceptions.GoodfilSecurityException;

import org.apache.log4j.Logger;
import org.richfaces.model.UploadItem;
import org.richfaces.event.UploadEvent;
import static ru.niir.goodfil.utils.Utils.s;
import ru.goodwill.TableModel;
import ru.goodwill.ExcelTable;
import ru.goodwillexceptions.FileException;
import ru.goodwillexceptions.ParseException;
import ru.goodwillexceptions.ModelException;
import ru.niir.goodfil.exceptions.ValidationException;

public class ImportRestsBean extends PageBean
{
    private final static Logger logger = Logger.getLogger(ImportRestsBean.class);

    public ImportRestsBean()
    {
        if (!getSecurityBean().getIsRoleAdministrator())
            throw new GoodfilSecurityException("Только администраторы имеют доступ к функции \"импорт остатков из Excel\"");
    }

    private String getSHARED_CATALOG() { return getValueOfDefault("import.rests.shared.catalog", "/usr/home/goodwill"); }

    private String getEXCEL_TABLE_P0() { return getValueOfDefault("import.rests.p0", "Код"); }
    private int getEXCEL_TABLE_P1() { return getValueOfDefault("import.rests.p1", 1); }
    private int getEXCEL_TABLE_P2() { return getValueOfDefault("import.rests.p2", 1); }
    private int getMAX_ERRORS() { return getValueOfDefault("import.rests.max.errors", 20); }

    private String getCODE() { return getValueOfDefault("import.rests.code", "Код"); }
    private String getREST() { return getValueOfDefault("import.pricelist.value", "Остатки"); }

    private String getValueOfDefault(String settingName, String defaultValue)
    {
        gf().createIfNotExists(settingName, defaultValue);
        return gf().get(settingName);
    }

    private int getValueOfDefault(String settingName, int defaultValue)
    {
        gf().createIfNotExists(settingName, String.valueOf(defaultValue));
        return gf().getInt(settingName);
    }

    public enum ImportMessageType
    {
        INFO,
        ERROR
    }

    public static class ImportMessage
    {
        public boolean getIsInfo()
        {
            return type == ImportMessageType.INFO;
        }

        public boolean getIsError()
        {
            return type == ImportMessageType.ERROR;
        }

        private ImportMessageType type;
        private String message;

        public ImportMessage()
        {
        }

        public ImportMessage(ImportMessageType type, String message)
        {
            this.type = type;
            this.message = message;
        }

        public ImportMessageType getType()
        {
            return type;
        }

        public void setType(ImportMessageType type)
        {
            this.type = type;
        }

        public String getMessage()
        {
            return message;
        }

        public void setMessage(String message)
        {
            this.message = message;
        }
    }

    private final List<ImportMessage> messages = new ArrayList<ImportMessage>();
    public List<ImportMessage> getMessages()
    {
        return messages;
    }

    public boolean hasImportErrors()
    {
        for (ImportMessage im : messages)
            if (im.getIsError())
                return true;
        return false;
    }

    public void addErrorMessage(String str)
    {
        messages.add(new ImportMessage(ImportMessageType.ERROR, str));
    }

    public void addInfoMessage(String str)
    {
        messages.add(new ImportMessage(ImportMessageType.INFO, str));
    }

    public void listener(UploadEvent event) throws Exception
    {
        logger.debug("listener()");
        messages.clear();

        UploadItem item = event.getUploadItem();
        String filename = item.getFileName();
        String ext = filename.substring(filename.lastIndexOf('.') + 1);
        File file = item.getFile();

        UUID uid = saveFile(file, ext);
        if (uid == null)
        {
            addErrorMessage("Невозможно скопировать файл в системную директорию. Обратитесь к администратору.");
            return;
        }

        importExcelFile(getSHARED_CATALOG() + File.separator + uid + "." + ext);
    }

    static class Rest
    {
        private String code;
        private int count;

        Rest(String code, String count)
        {
            this.code = s(code);
            this.count = (int) Float.parseFloat(s(count));
        }

        public String getCode()
        {
            return code;
        }

        public int getCount()
        {
            return count;
        }
    }

    private void importExcelFile(String filename)
    {
        logger.debug("Importing Excel pricelist");
        try
        {
            TableModel tableModel = new ExcelTable().initTableModel(new File(filename),
                                                                    getEXCEL_TABLE_P0(),
                                                                    getEXCEL_TABLE_P1(),
                                                                    getEXCEL_TABLE_P2());

            logger.debug("  cols: " + tableModel.getColumnCount() + ", rows: " + tableModel.getRowCount());

            //  Проверка того, что колонок нужное количество
            if (tableModel.getColumnCount() != 2)
                addErrorMessage("Неверное количество колонок в файле: " + tableModel.getColumnCount() + " (а должно быть 2).");

            if (hasImportErrors()) return;
            addInfoMessage("Количество колонок в порядке");

            //  Проверка того, что все нужные колонки есть
//            if (!tableModel.getColumnName(0).equals(getCODE()))
//                addErrorMessage("Колонка 1 имеет неверный заголовок: \"" + tableModel.getColumnName(0) + "\" (а должен быть: \"" + getCODE() + "\").");
//            if (!tableModel.getColumnName(1).equals(getREST()))
//                addErrorMessage("Колонка 2 имеет неверный заголовок: \"" + tableModel.getColumnName(1) + "\" (а должен быть: \"" + getREST() + "\").");

            if (hasImportErrors()) return;
            addInfoMessage("Наименования колонок в порядке");

            List<Rest> items = new ArrayList<Rest>();
            for(int y = 1; y < tableModel.getRowCount(); y++)
            {
                try
                {
                    items.add(new Rest(tableModel.getValueAt(y, 0), tableModel.getValueAt(y, 1)));
                }
                catch (NumberFormatException nfe)
                {
                    addErrorMessage("Строка " + String.valueOf(y + 1) + " имеет неверное значение в графе \"Остатки\": " + tableModel.getValueAt(y, 1) + ". Значение должно быть числом.");
                }
            }

            if (hasImportErrors()) return;

            addInfoMessage("Загружено " + items.size() + " строк (проверьте!).");
            addInfoMessage("Копирование в БД...");

            int okCount = 0;

            for (Rest item : items)
            {
                try
                {
                    logger.debug("rest item: " + item);
                    gf().updateGoodCount_Unsafe(item.getCode(), item.getCount());
                    okCount++;
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                    addErrorMessage(e.toString());
                }

            }
            addInfoMessage("Загружено успешно : " + okCount + " записей");
            addInfoMessage("Не загружено      : " + String.valueOf(items.size() - okCount) + " записей");
            addInfoMessage("ВСЕГО             : " + items.size() + " записей");
        }
        catch (ModelException me)
        {
            logger.error(me.getError().getDescription());
            me.printStackTrace();

            addErrorMessage("Ошибка чтения файла (2)");
        }
        catch (FileException fe)
        {
            logger.error(fe.getError().getDescription());
            fe.printStackTrace();

            addErrorMessage("Невозможно загрузить файл");
        }
        catch (ParseException pe)
        {
            logger.error(pe.getError().getDescription());
            pe.printStackTrace();

            addErrorMessage("Ошибка чтения файла");
        }
    }

    public synchronized UUID saveFile(File inFile, String ext)
    {
        assert inFile != null;
        assert ext != null;

        UUID newId = UUID.randomUUID();
        String newFilePath = getSHARED_CATALOG() + File.separator + newId + "." + ext;
        logger.debug("New file path: " + newFilePath);

        try
        {
            File outFile = new File(newFilePath);
            copyFile(inFile, outFile);
            return newId;
        }
        catch (IOException e)
        {
            logger.error(e);
            e.printStackTrace();

            return null;
        }
    }

    private static void copyFile(File in, File out) throws IOException
    {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try
        {
            fis  = new FileInputStream(in);
            fos = new FileOutputStream(out);

            byte[] buf = new byte[1024];
            int i;
            while ((i = fis.read(buf)) != -1) fos.write(buf, 0, i);
        }
        finally
        {
            if (fis != null) fis.close();
            if (fos != null) fos.close();
        }
    }



}